package gestIT;

import java.util.Iterator;
import java.util.Vector;

/**
 * Subclass of TmpExp that represent a complex building block.
 * A complex building block represent the operator of OrderIndipendence
 *
 * @author nicola
 *
 */
public class ComplexTmpExp extends TmpExp {

	/** The current operator (always OrderIndipendence) */
	public TmpOperator operator;
	/** Vector of all the operands */
	public Vector<TmpExp> operands;
	/** Vector of flags for the operand (true if the operand is completed, false otherwise) */
	public Vector<Boolean> completion;
	
	/**
	 * Constructor that return a new empty ComplexTmpExp
	 */
	public ComplexTmpExp(){
		operator = TmpOperator.OrderIndependence;
		this.operands = new Vector<TmpExp>();
		this.completion = new Vector<Boolean>();
		this.type = ExpType.Complex;
	}
	
	/**
	 * Add a new operand to the complex building block 
	 * @param oper The operand to be added
	 */
	public void AddOperand(TmpExp oper){
		this.operands.add(oper);
		this.completion.add(false);
		oper.Parent = this;
		oper.addOnStateChangedListener(new StateChangedHandler() {
			
			@Override
			public void OnStateChanged(StateChangedEvent evt) {
				operand_OnStateChanged(evt);	
			}
		});
	}
	
	/**
	 * Remove an operand from the complex building block 
	 * @param oper The operand to be removed
	 */
	public void RemoveOperand(TmpExp oper){
		
		int posit = FindOperatorPosition(oper);
		if (posit == -1)
			return;
		
		this.operands.removeElementAt(posit);
		this.completion.removeElementAt(posit);
		oper.removeOnStateChangedListener(new StateChangedHandler() {
			
			@Override
			public void OnStateChanged(StateChangedEvent evt) {
				operand_OnStateChanged(evt);	
			}
		});
	}
	
	/**
	 * Return the operand at position i
	 * @param i The position of the requested operand
	 * @return The operand at position i
	 */
	public TmpExp GetOperand(int i){
		if (i >= 0 && i < operands.size())
			return operands.get(i);
		else
			return null;
	}
	
	/**
	 * Return an Iterator object that can be used to access all the TmpExp object in a ComplexTmpExp object
	 * @return The Iterator<TmpExp>
	 */
	public Iterator<TmpExp> GetOperands(){
		return operands.iterator();
	}
	
	/**
	 * Return the position of a specific operand
	 * @param exp The operand that you want to find
	 * @return The position of the requested operand
	 */
	private int FindOperatorPosition(TmpExp exp){
		
		TmpExp tmpgest;
		int i = 0;
		
		for (i = 0; i < operands.size(); i++){
			tmpgest = operands.get(i);
			if (exp.equals(tmpgest))
				return i;
		}
		return -1;		
	}
	
	@Override
	public void SetExecState(ExecState st, Token tk){
		int i;
		switch (operator) {
		case OrderIndependence:
			
			TmpExp tmpgest;
			switch (st) {
			case Enabled:
				
				if (this.state == ExecState.Disabled || this.state == ExecState.Performing){
                    for (i = 0; i < completion.size(); i++)
                    	completion.set(i,false);
				}
				for (i = 0; i < operands.size(); i++){
					tmpgest = operands.get(i);
					if (tmpgest.state == ExecState.Disabled || tmpgest.state == ExecState.Completed);
						tmpgest.SetExecState(ExecState.Enabled, tk);
				}
				break;

			case Performing: 
				break;
				
			case Disabled:
				for (i = 0; i < operands.size(); i++){
					tmpgest = operands.get(i);
					tmpgest.SetExecState(ExecState.Disabled, tk);
				}
				break;
				
			case Completed:
				if (this.Iterative == true)
					this.SetExecState(ExecState.Enabled, tk);
				break;
			}			
			break;

		default: break;
		}
		super.SetExecState(st, tk);
	}
	
	
	void operand_OnStateChanged(StateChangedEvent evt){
		int i, pos;
		TmpExp sender = evt.getSender();
		ExpEventArgs arg = evt.getEventArgs();
		Token tk = evt.getToken();
		
		this.SetExecState(sender.state, tk);
		switch (sender.state) {
		case Completed:
			
			pos = FindOperatorPosition(sender);
			if (pos >= 0){
				this.completion.set(pos, true);
				
				boolean alldone = true;
				for (i = 0; i<completion.size(); i++)
					alldone = alldone && completion.get(i).booleanValue();
				
                if (alldone)
                {
                    this.SetExecState(ExecState.Completed, tk);
                    RaiseCompleted(this, arg, tk);
                    RaiseOnStateChanged(this, arg, tk);
                }
                else
                {
                    this.SetExecState(ExecState.Performing, tk);
                    RaisePerforming(this, arg, tk);
                    RaiseOnStateChanged(this, arg, tk);
                }
			}
			break;

		case Performing:
			pos = FindOperatorPosition(sender);
			if (pos >= 0){
				for (i = 0; i<operands.size(); i++){
					if (!(completion.get(i).booleanValue()))
						operands.get(i).SetExecState(ExecState.Disabled, tk);
				}
				
				this.SetExecState(ExecState.Performing, tk);
				RaisePerforming(this, arg, tk);
				RaiseOnStateChanged(this, arg, tk);
			}
			break;
			
		case Error:
			this.SetExecState(ExecState.Error, tk);
			RaiseError(this, arg, tk);
			RaiseOnStateChanged(this, arg, tk);
			if (this.Iterative && tk != null){
				// avoid enabling null token
				this.SetExecState(ExecState.Enabled, tk);
			}
			break;
		}
		
	}
}
